package xyz.scootaloo.kami.cloud.util

import io.vertx.core.Future
import io.vertx.core.buffer.Buffer
import io.vertx.core.json.JsonObject
import io.vertx.ext.auth.User
import io.vertx.ext.auth.jwt.JWTAuth
import io.vertx.kotlin.core.json.jsonObjectOf
import io.vertx.kotlin.ext.auth.jwt.jwtAuthOptionsOf
import io.vertx.kotlin.ext.auth.jwtOptionsOf
import io.vertx.kotlin.ext.auth.pubSecKeyOptionsOf
import xyz.scootaloo.kami.cloud.lang.Global
import xyz.scootaloo.kami.cloud.lang.Stateless
import xyz.scootaloo.kami.cloud.model.core.AccessLevel
import xyz.scootaloo.kami.cloud.model.core.UserPrincipal

/**
 * @author flutterdash@qq.com
 * @since 2022/4/12 21:30
 */
@Stateless
object JwtHelper {



    /**
     * 签发 jwt
     */
    fun issueJwt(id: Int, username: String, role: Int): String {
        return issueJwt(UserPrincipal(id, username, role))
    }

    private fun issueJwt(tokenObject: UserPrincipal): String {
        return provider.generateToken(JsonObject.mapFrom(tokenObject), defJwtOptions)
    }

    /**
     * 验证 jwt
     */
    fun authenticate(jwt: String): Future<User> {
        // 忽略jwt过期问题
        return provider.authenticate(jsonObjectOf("token" to jwt, "ignoreExpiration" to true))
    }

    fun guestPrincipal(): JsonObject = guestUserPrincipalJson.copy()

    // configurations

    private val provider: JWTAuth by lazy { createJwtProvider() }
    private val defJwtOptions by lazy {
        jwtOptionsOf(
            ignoreExpiration = true,
            issuer = "kami"
        )
    }

    private fun createJwtProvider() = JWTAuth.create(Global.VERTX_REF, jwtAuthOptions())
    private fun jwtAuthOptions() = jwtAuthOptionsOf(jwtOptions = defJwtOptions).addPubSecKey(pubSecKey())
    private fun pubSecKey() = pubSecKeyOptionsOf("HS256", pubSecretKeyBuf)

    private val pubSecretKeyBuf = Buffer.buffer("kami-cloud-final flutterdash@qq.com")
    private val guestUserPrincipalJson: JsonObject by lazy {
        JsonObject.mapFrom(
            UserPrincipal(
                id = -1,
                username = "guest",
                role = AccessLevel.GUEST
            )
        )
    }
}